package com.ideal.gpt.ability.docqa.splitter;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ideal.gpt.ability.common.NlpJob;
import com.ideal.gpt.ability.docqa.QaFiller;
import com.lzwork.gpt.utility.common.Passage;
import com.lzwork.utility.collection.CollUtility;
import com.lzwork.utility.dictionary.SetDictionary;
import com.lzwork.utility.file.LineContent;
import com.lzwork.utility.logger.LOGGER;
import com.lzwork.utility.logger.LOGGER.LogType;
import com.lzwork.utility.pair.Pair;
import com.lzwork.utility.pair.StringPair;
import com.lzwork.utility.str.StrUtility;
import com.lzwork.utility.str.StrUtility.CheckNull;
import com.lzwork.web.data.CallResultInfo;

/**
 * @author LiZheng
 * @date 2023年9月21日 上午10:38:28
 */

public class ResponseSplitter
{
	public class SplitResult extends CallResultInfo<List<StringPair>>
	{
		public SplitResult(List<StringPair> target, Object info)
		{
			super(target, info);
		}

		public boolean isEmpty()
		{
			return size() == 0;
		}

		public int size()
		{
			if (CollUtility.hasData(target))
				return target.size();
			return 0;
		}
	}

	public static class ChoiceResult
	{
		public ChoiceResult(String input)
		{
			this.input = input;
		}

		String input;
		String qFull = "";
		String q = "";
		String a = "";
		List<String> choices = new ArrayList<>();
		boolean detail = false;

		public boolean isValid()
		{
			return StrUtility.stringValid(qFull) & StrUtility.stringValid(a);
		}

		public List<String> toData(boolean addState)
		{
			List<String> data = new ArrayList<>();

			if (addState)
				data.add(state());

			data.add(qFull);
			data.add(q);
			data.add(a);
			data.addAll(choices);

			return data;
		}

		public final static String S_FULL = "Full";
		public final static String S_SIMPLE = "Simple";
		public final static String S_EMPTY = "Empty";

		public String state()
		{
			if (isValid())
			{
				return detail ? S_FULL : S_SIMPLE;
			}

			return S_EMPTY;
		}
	}

	public ResponseSplitter(int max, boolean log)
	{
		this.max = max;
		this.log = log;
	}

	protected int max = 1;
	protected boolean log;

	public SplitResult splitResponse(String response, int type)
	{
		List<StringPair> result = null;
		String info = "";

		if (type == 1)
		{
			PairPrefixGroup perfix = new PairPrefixGroup();
			perfix.append("问题", "回答");
			perfix.append("问题", "答案");

			result = perfix.splitContentPairs(response);

			if (result.size() == 0)
			{
				info = LOGGER.warn("Invalid result for " + info + "[mode " + perfix.mode() + "]:\n" + response);
			} else if (result.size() < max)
			{
				info = LOGGER.warn(
						"No enough result for " + info + "[" + result.size() + "/" + max + "][mode " + perfix.mode() + "]:\n");
			}
		} else if (type == 2)
		{
			ChoiceResult cr = splitChoice(response, false);
			if (cr.isValid())
			{
				result = new ArrayList<>();
				result.add(new StringPair(cr.qFull, cr.a));
			}

		} else if (type == 3)
		{
			PairPrefixGroup perfix = new PairPrefixGroup();

			perfix.append("判断题", "答案");
			perfix.append("题目", "答案");
			perfix.append("判断题", "答案是");
			perfix.append("判断题", "答");

			result = perfix.splitContentPairs(response);

		} else if (type == 4 || type == 14 || type == 24)
		{
			List<JSONObject> picked = Passage.pickJsonObjects(response, 1, LogType.Simple);
			if (picked.isEmpty())
			{
				PairPrefixGroup perfix = new PairPrefixGroup();
				boolean noA = false;
				if (type == 24)
				{
					perfix.append("sent", "keyword", false, true);
					noA = true;
				}
				perfix.append("核心句子", "关键词", false, noA);
				perfix.append("core_sentences", "core_words", false, noA);
				perfix.append("核心句子", "核心词", false, noA);

				result = perfix.splitByParagraph(response);

				if (type == 14)
				{
					SetDictionary<String> data = splitKeywords(result);
					result = makeFillQuestions(data);
				}
			} else
			{
				result = new ArrayList<>();
				for (JSONObject obj : picked)
				{
					SetDictionary<String> data = splitKeywords(obj);

					if (type == 14)
						result.addAll(makeFillQuestions(data));
					else
					{
						for (Entry<String, Set<String>> e : data.entrySet())
						{
							result.add(new StringPair(e.getKey(), StrUtility.combineString(e.getValue(), ",")));
						}
					}
				}
			}
		} else
			info = "Unknown split type: " + type;

		return new SplitResult(result, info);
	}

	public static ChoiceResult splitChoice(String input, boolean detail)
	{
		// for result from 13b
		int aSplit = input.lastIndexOf("正确");
		int len = input.length();

		ChoiceResult result = new ChoiceResult(input);

		int delta = Math.abs(aSplit - len);
		int maxDelta = 20;

		if (aSplit < 0 || delta > maxDelta)
		{
			aSplit = input.lastIndexOf("选项");
			delta = Math.abs(aSplit - len);
		}
		if (aSplit < 0 || delta > maxDelta)
		{
			aSplit = input.lastIndexOf("答案");
			delta = Math.abs(aSplit - len);
		}

		if (aSplit < 0 || delta > maxDelta)
			return result;

		result.a = input.substring(aSplit);
		result.qFull = input.substring(0, aSplit);

		if (detail)
		{
			Pair<String, List<String>> detailResult = splitChoiceDetail(result.qFull);
			result.q = detailResult.first();
			result.choices = detailResult.second();
		}

		return result;
	}

	public static Pair<String, List<String>> splitChoiceDetail(String input)
	{
		int split = input.indexOf("选项");
		if (split < 0)
			split = input.indexOf("A.");

		if (split < 0)
			return new Pair<>("", null);

		String q = input.substring(0, split);
		List<String> choice = new ArrayList<>();

		String content = input.substring(split);

		char c = 'A';
		byte add = 0;

		while (true)
		{
			if (add >= 26)
				break;

			char x = (char) (c + add);
			String head = x + ".";

			split = content.indexOf(head);
			if (split < 0)
			{
				choice.add(content);
				break;
			}

			if (add > 0)
			{
				String before = content.substring(0, split);
				choice.add(before);
			}
			add++;

			content = content.substring(split);
		}

		return new Pair<>(q, choice);
	}

	public List<StringPair> makeFromKeywords(List<StringPair> keycontents)
	{
		List<StringPair> result = new ArrayList<>();

		for (StringPair input : keycontents)
		{
			result.add(makeFromKeywords(input));
		}

		return result;
	}

	public StringPair makeFromKeywords(StringPair sp)
	{
		String q = sp.getKey();
		String[] as = sp.getValue().split("、");

		return makeFromKeywords(q, Arrays.asList(as));
	}

	public StringPair makeFromKeywords(String sent, String[] words)
	{
		return makeFromKeywords(sent, Arrays.asList(words));
	}

	public StringPair makeFromKeywords(String sent, Collection<String> words)
	{
		List<String> topick = new ArrayList<>();
		for (String word : words)
		{
			if (StrUtility.stringValid(word) && sent.contains(word))
				topick.add(word);
		}

		if (topick.isEmpty())
		{
			topick.addAll(NlpJob.splitCoreWords(sent, true));

			if (log)
			{
				if (words.isEmpty())
					LOGGER.log(LOGGER.PARSE, "No valid keyword for sentence: " + sent);
				else
					LOGGER.log(LOGGER.PARSE, "No valid keyword for sentence: " + sent + ". Use segments instead.");
			}
		}

		return QaFiller.makeQuestion(sent, StrUtility.objectsToStrings(CheckNull.RemoveEmpty, true, topick));
	}

	public List<StringPair> makeFillQuestions(SetDictionary<String> data)
	{
		List<StringPair> result = new ArrayList<>();

		for (Entry<String, Set<String>> sp : data.entrySet())
		{
			result.add(makeFromKeywords(sp.getKey(), sp.getValue()));
		}

		return result;
	}

	public List<StringPair> makeFillQuestions(String jstr)
	{
		List<JSONObject> picked = Passage.pickJsonObjects(jstr, 1, LogType.Simple);
		if (picked.isEmpty())
		{
			if (log)
				LOGGER.log(LOGGER.PARSE, "Exception while parse json input: " + jstr);
			return new ArrayList<>();
		}

		return makeFillQuestions(picked);
	}

	public List<StringPair> makeFillQuestions(List<JSONObject> jObj)
	{
		List<StringPair> result = new ArrayList<>();
		for (JSONObject obj : jObj)
		{
			SetDictionary<String> data = splitKeywords(obj);
			result.addAll(makeFillQuestions(data));
		}

		return result;
	}

	public static String removeQuote(String input)
	{
		String str = input;
		if (str.startsWith("\""))
			str = str.substring(1);

		if (str.endsWith("\""))
		{
			if (str.length() == 1)
				return "";
			str = str.substring(0, str.length() - 1);
		}

		return str;
	}

	public SetDictionary<String> splitKeywords(List<StringPair> spInput)
	{
		SetDictionary<String> data = new SetDictionary<>();
		for (StringPair sp : spInput)
		{
			String key = sp.getKey();
			Set<String> holder = data.pick(key);

			String vString = sp.getValue().replace("，", " ");
			vString = vString.replace(",", " ");

			String[] parts = vString.split("[ ]|[、]");

			for (String str : parts)
			{
				str = removeQuote(str);
				if (StrUtility.stringValid(str))
					holder.add(str);
			}
		}

		return data;
	}

	public SetDictionary<String> splitKeywords(String jStr)
	{
		List<JSONObject> picked = Passage.pickJsonObjects(jStr, 1, LogType.Simple);
		if (picked.isEmpty())
		{
			if (log)
				LOGGER.log(LOGGER.PARSE, "Exception while parse json input: " + jStr);
			return new SetDictionary<>();
		}

		return splitKeywords(picked.get(0));
	}

	public SetDictionary<String> splitKeywords(JSONObject jObj)
	{
		SetDictionary<String> result = new SetDictionary<>();
		JSONArray sent = null;
		List<String> allWords = null;

		Object sentObj = CollUtility.pickOneOf(jObj, "core_sentences", "core_sentence", "核心句子");

		if (sentObj instanceof JSONArray)
			sent = (JSONArray) sentObj;
		else
		{
			sent = new JSONArray();
			if (sentObj != null)
				sent.add(sentObj.toString());
		}

		Object kw = CollUtility.pickOneOf(jObj, "core_words", "keywords", "核心词");
		if (kw == null)
			kw = new JSONArray();

		if (kw instanceof JSONArray)
			allWords = StrUtility.objectsToStrings(CheckNull.RemoveEmpty, true, (JSONArray) kw);
		else if (kw instanceof JSONObject)
		{
			allWords = new ArrayList<>();
			for (Entry<String, Object> e : ((JSONObject) kw).entrySet())
			{
				allWords.add(e.getValue().toString());
			}
		} else
		{
			allWords = new ArrayList<>();
		}

		if (sent.isEmpty())
		{
			if (log)
				LOGGER.log(LOGGER.PARSE, "No valid result from json object: " + jObj.toJSONString());
			return result;
		}

		for (Object o : sent)
		{
			String sentStr = o.toString();

			Set<String> words = new HashSet<>();
			for (String w : allWords)
			{
				if (!sentStr.contains(w))
					continue;

				if (w.length() < sentStr.length())
					words.add(w);
				else
				{
					words.addAll(NlpJob.splitCoreWords(w, true));
				}
			}

			result.pick(sentStr).addAll(words);
		}

		if (result.isEmpty() && log)
		{
			LOGGER.log(LOGGER.PARSE, "No valid result from sentence: " + sent + " and words: " + allWords);
		}

		return result;
	}

	public static void main(String[] args)
	{
		String response = "1. 长三角生态绿色一体化发展示范区涉税事项跨区域通办清单包括以下内容：信息报告类、发票办理类、信息查询类和证明开具类等。\n关键词：类、报告、发票";

		File file = new File("v:/npu/temp.txt");
		response = LineContent.loadString(file);

		ResponseSplitter splitter = new ResponseSplitter(3, false);
		SplitResult qasp = splitter.splitResponse(response, 14);

		if (qasp.isEmpty())
		{
			LOGGER.log(LOGGER.PARSE, "Get keywords from response fail: " + response);
		} else
		{
			String result = QaFiller.resultToString(qasp.target(), false);

			System.out.println(result);
		}
	}
}
